package arcane.object.collections;

import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Queue;

public class ArrayQueue<T> extends AbstractCollection<T> implements Queue<T> {
	private int EXPAND_FACTOR;
	private int count;
	private T[] queue;

	public ArrayQueue() {
		this(10, 10);
	}

	public ArrayQueue(int initialSize, int expandFactor) {
		count = 0;
		queue = (T[]) (new Object[initialSize]);
		EXPAND_FACTOR = expandFactor;
	}

	public boolean offer(T t) {
		if (++count >= queue.length) {
			T[] ary = (T[]) (new Object[queue.length + EXPAND_FACTOR]);
			System.arraycopy(queue, 0, ary, 0, count);
			queue = ary;
		}
		queue[count] = t;
		return true;
	}

	public boolean contains(Object t) {
		for (int i = 0; i < queue.length; i++) {
			if (queue[i].equals(t))
				return true;
		}
		return false;
	}

	public boolean retainAll(Collection<?> c) {
		boolean flag = false;
		for (int i = 0; i < count; i++) {
			if (!c.contains(queue[i])) {
				flag = true;
				remove(queue[i]);
			}
		}
		return flag;
	}

	public T poll() {
		if (count == 0)
			return null;
		T result = queue[0];
		shiftForward(0);
		return result;
	}

	public T remove() {
		if (count == 0) {
			throw new NoSuchElementException("Queue is empty.");
		} else {
			T t = queue[0];
			shiftForward(0);
			return t;
		}
	}

	public boolean remove(Object obj) {
		for (int i = 0; i < count; i++)
			if (obj.equals(queue[i])) {
				shiftForward(i);
				return true;
			}
		return false;
	}

	private void shiftForward(int index) {
		count--;
		for (int i = 0; i < count; i++)
			queue[i] = queue[index + 1];
		queue[count] = null;
	}

	public T peek() {
		return queue[0];
	}

	public T element() {
		if (count == 0)
			throw new NoSuchElementException("Queue is empty.");
		else
			return queue[0];
	}

	public boolean isEmpty() {
		return count == 0;
	}

	public int size() {
		return count;
	}

	public Iterator<T> iterator() {
		return new ListIterator<T>(this);
	}

	public void clear() {
		for (int i = 0; i < count; i++)
			queue[i] = null;
		count = 0;
	}

	public T[] toArray() {
		T[] t = (T[]) (new Object[count]);
		for (int i = 0; i < count; i++)
			t[i] = queue[i];
		return t;
	}
}